package com.globallogic.vkulyk.SSHTool;

import org.junit.runner.RunWith;
import org.junit.*;
import org.mockito.*;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.core.classloader.annotations.*;
import org.powermock.api.mockito.PowerMockito;

@RunWith(PowerMockRunner.class)
@PrepareForTest(ActionExecutorFactory.class)
public class Unit_ActionExecutorFactory extends SSHToolTester {
	private static final String RETURN_IS_NOT_INSTANCE_OF_COMMAND_EXECUTOR = "Return is not instance of CommandExecutor";
	private static final String RETURN_IS_NOT_INSTANCE_OF_FILE_PUTTER = "Return is not instance of FilePutter";
	private static final String RETURN_IS_NOT_INSTANCE_OF_FILE_GETTER = "Return is not instance of FileGetter";
	private static final String RETURN_IS_NOT_INSTANCE_OF_SCRIPT_EXECUTOR = "Return is not instance of ScriptExecutor";
	private SocketDataKeeper mockedSocketData = null;
	private ActionDataKeeper mockedActionData = null;
	ActionExecutor returnedExecutor = null;

	@Test
	public void shouldInstantiateCommandExecutorWithCorrectArgsAndReturnIt_whenCallExecuteWithCommandExecutionData()
			throws Exception {
		// given
		setup("execute_command");
		CommandExecutor mockedCommandExecutor = Mockito
				.mock(CommandExecutor.class);
		Mockito.when(
				((CommandExecutionDataKeeper) mockedActionData).getCommand())
				.thenReturn(command);
		PowerMockito
				.whenNew(CommandExecutor.class)
				.withArguments(Mockito.anyString(), Mockito.anyInt(),
						Mockito.anyString(), Mockito.anyString(),
						Mockito.anyString()).thenReturn(mockedCommandExecutor);

		// when
		returnedExecutor = new ActionExecutorFactory(mockedSocketData,
				mockedActionData).defineAndCreateActionExecutor();

		// then
		PowerMockito.verifyNew(CommandExecutor.class, Mockito.times(1))
				.withArguments(Mockito.eq(host), Mockito.eq(port),
						Mockito.eq(user), Mockito.eq(password),
						Mockito.eq(command));
		Assert.assertTrue(RETURN_IS_NOT_INSTANCE_OF_COMMAND_EXECUTOR,
				returnedExecutor instanceof CommandExecutor);
	}

	@Test
	public void shouldInstantiateFilePutterWithCorrectArgsAndReturnIt_whenCallExecuteWithPutFileData()
			throws Exception {
		// given
		setup("put");
		FilePutter mockedFilePutter = Mockito.mock(FilePutter.class);
		Mockito.when(((FileCopyDataKeeper) mockedActionData).getSrcFile())
				.thenReturn(srcFileForPut);
		Mockito.when(((FileCopyDataKeeper) mockedActionData).getDstDir())
				.thenReturn(dstDirForPut);
		PowerMockito
				.whenNew(FilePutter.class)
				.withArguments(Mockito.anyString(), Mockito.anyInt(),
						Mockito.anyString(), Mockito.anyString(),
						Mockito.anyString(), Mockito.anyString())
				.thenReturn(mockedFilePutter);

		// when
		returnedExecutor = new ActionExecutorFactory(mockedSocketData,
				mockedActionData).defineAndCreateActionExecutor();

		// then
		PowerMockito.verifyNew(FilePutter.class, Mockito.times(1))
				.withArguments(Mockito.eq(host), Mockito.eq(port),
						Mockito.eq(user), Mockito.eq(password),
						Mockito.eq(srcFileForPut), Mockito.eq(dstDirForPut));
		Assert.assertTrue(RETURN_IS_NOT_INSTANCE_OF_FILE_PUTTER,
				returnedExecutor instanceof FilePutter);
	}

	@Test
	public void shouldInstantiateFileGetterWithCorrectArgsAndReturnIt_whenCallExecuteWithGetFileData()
			throws Exception {
		// given
		setup("get");
		FileGetter mockedFileGetter = Mockito.mock(FileGetter.class);
		Mockito.when(((FileCopyDataKeeper) mockedActionData).getSrcFile())
				.thenReturn(srcFileForGet);
		Mockito.when(((FileCopyDataKeeper) mockedActionData).getDstDir())
				.thenReturn(dstDirForGet);
		PowerMockito
				.whenNew(FileGetter.class)
				.withArguments(Mockito.anyString(), Mockito.anyInt(),
						Mockito.anyString(), Mockito.anyString(),
						Mockito.anyString(), Mockito.anyString())
				.thenReturn(mockedFileGetter);

		// when
		returnedExecutor = new ActionExecutorFactory(mockedSocketData,
				mockedActionData).defineAndCreateActionExecutor();

		// then
		PowerMockito.verifyNew(FileGetter.class, Mockito.times(1))
				.withArguments(Mockito.eq(host), Mockito.eq(port),
						Mockito.eq(user), Mockito.eq(password),
						Mockito.eq(srcFileForGet), Mockito.eq(dstDirForGet));
		Assert.assertTrue(RETURN_IS_NOT_INSTANCE_OF_FILE_GETTER,
				returnedExecutor instanceof FileGetter);
	}

	@Test
	public void shouldInstantiateScriptExecutorWithCorrectArgsAndReturnIt_whenCallExecuteWithScriptExecutionData()
			throws Exception {
		// given
		setup("execute_script");
		ScriptExecutor mockedScriptExecutor = Mockito
				.mock(ScriptExecutor.class);
		Mockito.when(((ScriptExecutionDataKeeper) mockedActionData).getScript())
				.thenReturn(script);
		PowerMockito
				.whenNew(ScriptExecutor.class)
				.withArguments(Mockito.anyString(), Mockito.anyInt(),
						Mockito.anyString(), Mockito.anyString(),
						Mockito.anyString()).thenReturn(mockedScriptExecutor);

		// when
		returnedExecutor = new ActionExecutorFactory(mockedSocketData,
				mockedActionData).defineAndCreateActionExecutor();

		// then
		PowerMockito.verifyNew(ScriptExecutor.class, Mockito.times(1))
				.withArguments(Mockito.eq(host), Mockito.eq(port),
						Mockito.eq(user), Mockito.eq(password),
						Mockito.eq(script));
		Assert.assertTrue(RETURN_IS_NOT_INSTANCE_OF_SCRIPT_EXECUTOR,
				returnedExecutor instanceof ScriptExecutor);
	}

	public void setup(String actionType) {
		setVarsFromPropertiesFile("testData/testing.properties");
		String actionDataSubclass = "";
		if (actionType.equals("execute_command")) {
			actionDataSubclass = "com.globallogic.vkulyk.SSHTool.CommandExecutionDataKeeper";
		} else if (actionType.equals("put") || actionType.equals("get")) {
			actionDataSubclass = "com.globallogic.vkulyk.SSHTool.FileCopyDataKeeper";
		} else if (actionType.equals("execute_script")) {
			actionDataSubclass = "com.globallogic.vkulyk.SSHTool.ScriptExecutionDataKeeper";
		}
		mockedSocketData = Mockito.mock(SocketDataKeeper.class);
		try {
			mockedActionData = (ActionDataKeeper) Mockito.mock(Class
					.forName(actionDataSubclass));
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Mockito.when(mockedSocketData.getHost()).thenReturn(host);
		Mockito.when(mockedSocketData.getPort()).thenReturn(port);
		Mockito.when(mockedActionData.getUser()).thenReturn(user);
		Mockito.when(mockedActionData.getPassword()).thenReturn(password);
		Mockito.when(mockedActionData.getType()).thenReturn(actionType);
	}

}
